package com.zg.datapush.handler.impl;

import cn.hutool.json.JSONUtil;
import com.zg.common.core.dao.datapush.entity.DpInterfaceConfig;
import com.zg.datapush.handler.CustomPushHandler;
import com.zg.datapush.handler.PushResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;

import java.util.List;
import java.util.Map;

/**
 * 示例自定义推送处理器
 * @author zg
 */
@Component
@Slf4j
public class ExampleCustomPushHandler implements CustomPushHandler {

    private final RestTemplate restTemplate = new RestTemplate();

    @Override
    public PushResult push(List<Map<String, Object>> pushData, Map<String, Object> config) {
        try {
            // 1. 获取配置参数
            String apiKey = (String) config.get("apiKey");
            String secretKey = (String) config.get("secretKey");
            String endpoint = (String) config.get("endpoint");

            // 2. 执行自定义认证逻辑
            String authToken = performCustomAuth(apiKey, secretKey);

            // 3. 转换数据格式
            String requestBody = convertDataFormat(pushData);

            // 4. 发送请求
            HttpHeaders headers = buildCustomHeaders("Bearer " + authToken);

            HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.postForEntity(endpoint, entity, String.class);

            // 5. 处理响应
            if (response.getStatusCode().is2xxSuccessful()) {
                PushResult result = PushResult.success("推送成功", response.getBody());
                result.setSuccessCount(pushData.size());
                result.setFailedCount(0);
                return result;
            } else {
                PushResult result = PushResult.failure("推送失败: " + response.getBody());
                result.setSuccessCount(0);
                result.setFailedCount(pushData.size());
                return result;
            }

        } catch (Exception e) {
            log.error("自定义推送处理器执行失败", e);
            PushResult result = PushResult.failure("推送异常: " + e.getMessage());
            result.setSuccessCount(0);
            result.setFailedCount(pushData.size());
            return result;
        }
    }

    /**
     * 单条数据推送方法（新增，支持单条推送模式）
     */
    public PushResult push(DpInterfaceConfig config, Map<String, Object> pushData) {
        try {
            // 1. 获取配置参数
            String apiKey = "xxx";
            String secretKey = "xxx";
            String endpoint = config.getUrl();

            // 2. 执行自定义认证逻辑
            String authToken = performCustomAuth(apiKey, secretKey);

            // 3. 转换单条数据格式
            String requestBody = convertSingleDataFormat(pushData);

            // 4. 发送请求
            HttpHeaders headers = buildCustomHeaders("Bearer " + authToken);

            HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.postForEntity(endpoint, entity, String.class);

            // 5. 处理响应
            if (response.getStatusCode().is2xxSuccessful()) {
                PushResult result = PushResult.success("单条推送成功", response.getBody());
                result.setSuccessCount(1);
                result.setFailedCount(0);
                return result;
            } else {
                PushResult result = PushResult.failure("单条推送失败: " + response.getBody());
                result.setSuccessCount(0);
                result.setFailedCount(1);
                return result;
            }

        } catch (Exception e) {
            log.error("单条自定义推送处理器执行失败", e);
            PushResult result = PushResult.failure("单条推送异常: " + e.getMessage());
            result.setSuccessCount(0);
            result.setFailedCount(1);
            return result;
        }
    }

    @Override
    public boolean testConnection(Map<String, Object> config) {
        try {
            String apiKey = (String) config.get("apiKey");
            String secretKey = (String) config.get("secretKey");
            String endpoint = (String) config.get("endpoint");

            // 执行连接测试
            String authToken = performCustomAuth(apiKey, secretKey);

            HttpHeaders headers = new HttpHeaders();
            headers.set("Authorization", "Bearer " + authToken);

            HttpEntity<String> entity = new HttpEntity<>(headers);
            ResponseEntity<String> response = restTemplate.exchange(
                endpoint + "/health", HttpMethod.GET, entity, String.class);

            return response.getStatusCode().is2xxSuccessful();

        } catch (Exception e) {
            log.error("连接测试失败", e);
            return false;
        }
    }

    /**
     * 自定义认证逻辑
     */
    private String performCustomAuth(String apiKey, String secretKey) {
        // 这里实现具体的认证逻辑
        // 例如：生成时间戳签名、调用认证接口等
        long timestamp = System.currentTimeMillis();
        String signature = generateSignature(apiKey, secretKey, timestamp);
        return apiKey + ":" + signature + ":" + timestamp;
    }

    /**
     * 生成HMAC-SHA256签名
     */
    private String generateSignature(String apiKey, String secretKey, long timestamp) {
        try {
            // 构建待签名字符串：apiKey + timestamp
            String stringToSign = apiKey + timestamp;

            // 使用HMAC-SHA256算法生成签名
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);

            byte[] signatureBytes = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));

            // 使用Base64编码
            return Base64.getEncoder().encodeToString(signatureBytes);

        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            log.error("生成签名失败", e);
            // 降级到简单hash算法
            String data = apiKey + secretKey + timestamp;
            return Integer.toHexString(data.hashCode());
        }
    }

    /**
     * 自定义数据格式转换（批量）
     */
    private String convertDataFormat(List<Map<String, Object>> data) {
        // 根据第三方系统要求转换数据格式
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("data", data);
        requestData.put("timestamp", System.currentTimeMillis());
        requestData.put("version", "1.0");
        requestData.put("format", "json");

        // 可以根据不同的第三方系统要求进行不同的格式转换
        // 例如：XML格式、特定的JSON结构、加密数据等
        return JSONUtil.toJsonStr(requestData);
    }

    /**
     * 自定义单条数据格式转换
     */
    private String convertSingleDataFormat(Map<String, Object> data) {
        // 根据第三方系统要求转换单条数据格式
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("data", data);
        requestData.put("timestamp", System.currentTimeMillis());
        requestData.put("version", "1.0");
        requestData.put("format", "json");
        requestData.put("type", "single");

        // 可以根据不同的第三方系统要求进行不同的格式转换
        // 例如：XML格式、特定的JSON结构、加密数据等
        return JSONUtil.toJsonStr(requestData);
    }

    /**
     * 构建自定义请求头
     */
    private HttpHeaders buildCustomHeaders(String authToken) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", authToken);
        headers.set("User-Agent", "DataPush-Service/1.0");
        headers.set("X-Request-ID", java.util.UUID.randomUUID().toString());

        // 可以根据配置添加更多自定义头
        String customHeaders = "customHeaders";
        if (customHeaders != null) {
            try {
                @SuppressWarnings("unchecked")
                Map<String, String> headerMap = JSONUtil.toBean(customHeaders, HashMap.class);
                headerMap.forEach(headers::set);
            } catch (Exception e) {
                log.warn("解析自定义请求头失败: {}", customHeaders, e);
            }
        }

        return headers;
    }
}
